﻿using System.Linq;
using Daemon.Common;
using Daemon.Common.Helpers;
using Daemon.Infrustructure.EF;
using Daemon.Repository.EF.Enums;
using Daemon.Repository.Contract;
using Daemon.Model;
using System;
using System.Linq.Expressions;
using System.Collections.Generic;
using Daemon.Model.Entities;

namespace Daemon.Repository.EF
{
	public class TakeAwayGoodRepository : Repository<TakeAwayGood>, ITakeAwayGoodRepository
	{
		private readonly ITakeAwayGoodRuleRepository _takeAwayGoodRuleRepository;

		private readonly ITakeAwayRuleDetailRepository _takeAwayRuleDetailRepository;

		protected override Expression<Func<TakeAwayGood, int>> PrimaryKeyExpression => r => r.Id;

		public TakeAwayGoodRepository(ApiDBContent context, ITakeAwayGoodRuleRepository takeAwayGoodRuleRepository, ITakeAwayRuleDetailRepository takeAwayRuleDetailRepository) : base(context)
		{
			_takeAwayGoodRuleRepository = takeAwayGoodRuleRepository;
			_takeAwayRuleDetailRepository = takeAwayRuleDetailRepository;
		}

		protected override IEnumerable<TakeAwayGood> IncludeRelationships(IEnumerable<TakeAwayGood> entities, ApiDBContent db)
		{
			SetGoodType(entities);

			SetGoodRuleInfo(entities);

			return base.IncludeRelationships(entities, db);
		}

		protected override void SaveRelationships(TakeAwayGood entity, TakeAwayGood entityWithRelationships, ApiDBContent db, short entityORMType)
		{
			SavePriceProperty(entity, entityWithRelationships);

			base.SaveRelationships(entity, entityWithRelationships, db, entityORMType);
		}

		private void SavePriceProperty(TakeAwayGood entity, TakeAwayGood entityWithRelationships)
		{
			if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, TakeAwayGoodRelationShipEnum.PriceProperty))
			{
				return;
			}

			_takeAwayRuleDetailRepository.SetRelationships(new List<Relationship>() { new Relationship() { Name = TakeAwayRuleDetailRelationShipEnum.AddPriceProeperty.ToString() } });
			entityWithRelationships.PriceProperty.ForEach(r =>
			{
				r.GoodId = entity.Id;
				r.ShopId = entity.ShopId;
				r.AddPriceProperty.ForEach(value =>
				{
					value.GoodId = entity.Id;
				});
			});

			_takeAwayRuleDetailRepository.DeleteRange(Context.TakeAwayRuleDetail.Where(r => r.GoodId == entity.Id));
			_takeAwayRuleDetailRepository.AddRangeWithRelationships(entityWithRelationships.PriceProperty);
		}

		private void SetGoodRuleInfo(IEnumerable<TakeAwayGood> entities)
		{
			if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, TakeAwayGoodRelationShipEnum.RuleInfo))
			{
				return;
			}

			var ruleIds = entities.Where(r => r.RuleId != null).Select(r => r.RuleId.Split(",")).SelectMany(r => r).Select(r => Convert.ToInt32(r)).ToList();
			_takeAwayGoodRuleRepository.SetRelationships(new List<Model.Entities.Relationship>() { new Model.Entities.Relationship() { Name = TakeAwayGoodRuleRelationShipEnum.RuleDetail.ToString() } });
			var ruleList = _takeAwayGoodRuleRepository.IncludeRelationships(Context.TakeAwayGoodRule.Where(r => ruleIds.Contains(r.Id)));

			foreach (var entity in entities)
			{
				if (entity.RuleId == null)
				{
					return;
				}

				var currentRuleIds = entity.RuleId.Split(',').Select(r => Convert.ToInt32(r)).ToList();
				var currentRuleList = ruleList.Where(r => currentRuleIds.Contains(r.Id)).ToList();
				entity.Property = currentRuleList.Where(r => r.Values != null).SelectMany(r => r.Values).ToList();
			}

			SetPriceProtertyInfo(entities);
		}

		private void SetPriceProtertyInfo(IEnumerable<TakeAwayGood> entities)
		{
			var ids = entities.Select(r => r.Id).ToList();
			_takeAwayRuleDetailRepository.SetRelationships(new List<Model.Entities.Relationship>() { new Model.Entities.Relationship() { Name = TakeAwayRuleDetailRelationShipEnum.DetailValue.ToString() } });
			var priceProperties = _takeAwayRuleDetailRepository.IncludeRelationships(Context.TakeAwayRuleDetail.Where(r => r.GoodId.HasValue && ids.Contains(r.GoodId.Value))).ToList().GroupBy(r => r.GoodId).ToDictionary(r => r.Key, r => r.ToList());
			foreach (var entity in entities)
			{
				if (priceProperties.TryGetValue(entity.Id, out List<TakeAwayRuleDetail> detailValues))
				{
					if (entity.Property != null)
					{
						entity.Property.AddRange(detailValues);
					}
					else
					{
						entity.Property = detailValues;
					}
				}
			}
		}

		private void SetGoodType(IEnumerable<TakeAwayGood> entities)
		{
			if (!RouteParameterHelper.CheckRouteParameter(RelationshipNames, TakeAwayGoodRelationShipEnum.GoodType))
			{
				return;
			}

			var typeIds = entities.Select(r => r.GroupId).ToList();
			var dicType = Context.TakeAwayGoodType.Where(r => typeIds.Contains(r.Id)).ToDictionary(r => r.Id, r => r.Name);
			foreach (var entity in entities)
			{
				if (dicType.TryGetValue(entity.GroupId, out string typeName))
				{
					entity.TypeName = typeName;
				}
			}
		}
	}
}
